;
; Copy routine to move 8K of code from $2000-$3EDF to $9000-AEDF slow enough for the EEPROM to handle it.
; Note: Everything is hard coded!
;
 
  .org $1000

.define              EQU     =

StackBase            =       $100

KEY_CONTROL          =       $D011
KEY_DATA             =       $D010
DSP_DATA             =       $D012
DSP_CONTROL          =       $D013
APPLE1_MON           =       $FF1F
BASIC_WARM           =       $E2B3
  
SourceAddr           =       $2000
DestAddr             =       $9000
DataLength           =       $1EDF



  
pSource              =       $A0
pDest                =       $A2
pEnd                 =       $A4
zpt1                 =       $F0          ;data at this location is saved/restored
MsgPointerLow        =       $F2
MsgPointerHi         =       $F3
SPACE                EQU             $A0
CR                   EQU             $8D
ESC                  EQU             $9B

CTRL                 EQU             $40

  jsr   DispString
  .byte CR
  .byte "FLASH UPDATE CFFA1 VER 1.0",CR,CR
  .byte "THIS PROGRAM WILL COPY",CR
  .byte "$2000-$3EDF TO $9000-AEDF",CR,CR
  .byte "TO ENABLE THE EEPROM FOR FLASHING", CR
  .BYTE "FLIP SWITCH S1-4 UP (ON).",CR
  .BYTE "THEN PRESS A KEY TO BEGIN...,",CR,CR
  .byte "TO ABORT: PRESS RESET BUTTON",0
   jsr     WaitForKey              ; wait for user to press any key

  jsr   DispString
  .byte CR,CR
  .byte "BEGIN COPY",CR,0

  ; set up source pointer  
  lda   #<SourceAddr
  sta   pSource
  lda   #>SourceAddr
  sta   pSource+1

  ; set up dest pointer
  lda   #<DestAddr
  sta   pDest
  lda   #>DestAddr
  sta   pDest+1

  ; Set up the end address
  lda    #<DestAddr + <DataLength
  sta    pEnd
  lda    #>DestAddr + >DataLength
  sta    pEnd+1
  

loop:
  ldy    #$00
  lda    (pSource),y
  sta    (pDest),y

  lda    #$07 ; 200uS
  jsr    Wait
  
  inc    pSource
  bne    incDest
  inc    pSource+1

incDest:
  inc    pDest
  bne    CheckForEnd
  inc    pDest+1
  
CheckForEnd:
  lda   pDest
  cmp   pEnd
  bne   loop
  lda   pDest+1
  cmp   pEnd+1
  bne   loop

  jsr   DispString
  .byte "COPY COMPLETE!",CR,0

  jsr   DispString
  .byte "BEGIN VERIFY:",CR,0
  ; set up source pointer  
  lda   #<SourceAddr
  sta   pSource
  lda   #>SourceAddr
  sta   pSource+1

  ; set up dest pointer
  lda   #<DestAddr
  sta   pDest
  lda   #>DestAddr
  sta   pDest+1

  ; Set up the end address
  lda    #<DestAddr + <DataLength
  sta    pEnd
  lda    #>DestAddr + >DataLength
  sta    pEnd+1
  

Verifyloop:
  ldy    #$00
  lda    (pDest),y
  cmp    (pSource),y
  bne    VerifyFailed
  
  inc    pSource
  bne    VerifyincDest
  inc    pSource+1

VerifyincDest:
  inc    pDest
  bne    VerifyCheckForEnd
  inc    pDest+1
  
VerifyCheckForEnd:
   lda   pDest
   cmp   pEnd
   bne   Verifyloop
   lda   pDest+1
   cmp   pEnd+1
   bne   Verifyloop

   jsr   DispString
   .byte "VERIFY COMPLETE!",CR,0
   
   jmp  $FF1F   ;jmp to monitor  

VerifyFailed:
   pha
   
   jsr   DispString
   .byte "VERIFY FAILED AT LOCATION:",0
   tya
   clc
   adc  pDest
   pha
   lda  pDest+1
   adc  #0
   jsr  DispByteWithDollarSign
   pla
   jsr  DispByte
   
   jsr   DispString
   .byte "DATA:",0
   pla
   jsr  DispByteWithDollarSign
   jsr  DispCR
   
   jmp  $FF1F   ;jmp to monitor  
   
   
;------------------------------------------------------------------------------
;  Wait - Copy of Apple's wait routine. Can't use ROM based routine in case
;         ROM is not active when we need it.
;
; Input:
;       A = desired delay time, where Delay(us) = .5(5A^2 + 27A + 26)
;       or more usefully: A = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7
;
; CPU Registers changed:  A, P
;
Wait:
   sec

Wait2:
   pha

Wait3:
   sbc  #1
   bne  Wait3
   pla
   sbc  #1
   bne  Wait2
   rts

;------------------------------------------------------------------------------
; DispByte - Sends a Hex byte to the console
; Input:
;       A = Hex number to display
; Ouput:
;       None
;
; CPU Registers changed:  A, P
;
DispByteWithDollarSign:
   jsr DispString
   .byte "$",0
DispByte:
   pha
   lsr a
   lsr a
   lsr a
   lsr a
   jsr Nibble
   pla
Nibble:
   and #$0F
   ora #'0'
   cmp #'0'+10
   bcc @digit
   adc #6
@digit:
   bne DispChar   ; always taken

;------------------------------------------------------------------------------
; DispChar, DispCR - Sends a char to the Apple1 console
;
; Input:
;       A = Character to Send
; Ouput:
;
; ZeroPage Usage:
;       None
;
; CPU Registers changed:  Acc, P
;
; X and Y are preserved.
;
DispCR:
   lda #CR
DispChar:
; Wait until display is ready
   bit      DSP_DATA
   bmi      DispChar
; Send character to display hardware
   sta      DSP_DATA
   rts

;------------------------------------------------------------------------------
; DispString - Sends a String to the Apple1's console
; Input:
;       string must immediately follow the JSR to this function
;       and be terminated with zero byte.
; Ouput:
;       None
;
; ZeroPage Usage:
;       MsgPointerLow, MsgPointerHi   (saved and restored)
;
; CPU Registers changed:  P
;
DispString:
   pha                          ;save the Acc reg
   txa
   pha                          ;save the X reg
   tya
   pha                          ;save the Y reg
   tsx                          ;put the stack pointer in X
   lda  MsgPointerHi
   pha                          ;push zero page location on stack
   lda  MsgPointerLow
   pha                          ;push zero page location on stack

   lda  StackBase+4,x           ;determine the location of message to display
   clc
   adc  #$01                    ;add 1 because JSR pushes the last byte of its
   sta  MsgPointerLow           ; destination address on the stack

   lda  StackBase+5,x
   adc  #0
   sta  MsgPointerHi

@dss1:
   ldy  #0
   lda  (MsgPointerLow),y
   beq  @dssend
   jsr  DispChar                  ;display message
   inc  MsgPointerLow
   bne  @dss1
   inc  MsgPointerHi
   bne  @dss1

@dssend:

   lda  MsgPointerHi
   sta  StackBase+5,x
   lda  MsgPointerLow
   sta  StackBase+4,x           ;fix up the return address on the stack.

   pla
   sta  MsgPointerLow           ;restore zero page location
   pla
   sta  MsgPointerHi            ;restore zero page location
   pla
   tay
   pla
   tax
   pla
   rts                          ;return to location after string's null.
;------------------------------------------------------------------------------
; WaitForKey - Wait until a key is pressed. Returns key stroke in Acc
; Input:
;      None
; Ouput:
;      Acc = ASCII value of key pressed
;
; X and Y are preserved.
;
WaitForKey:
    lda     KEY_CONTROL
    bpl     WaitForKey
    lda     KEY_DATA
    rts

